import enum
from operator import index
import pathlib
import time
import re
import typing
import os
from numpy import common_type
import yaml
import ctypes
import psutil
import subprocess
import requests
import winsound
import datetime
from selenium.webdriver.edge.webdriver import WebDriver
from selenium.webdriver.edge.service import Service
from selenium.webdriver.edge.options import Options
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
from selenium.common.exceptions import *
from rich import print




def Custom_Message(parent_hwnd: int = 0, title: str = 'default_title', text: str = 'default_text', type: int = 0) -> int:
    """
    显示自定义消息框。

    该函数通过 ctypes 调用 Windows API 来显示一个带有自定义内容和标题的消息框。
    可以用于快速在 Windows 应用程序中创建消息提示。

    Args:
        parent_hwnd (int): 父窗口的窗口句柄。默认值为 0，表示没有父窗口。
        title (str): 消息框的标题。默认值为 'default_title'。
        text (str): 消息框的内容。默认值为 'default_text'。
        type (int): 消息框的类型，决定了消息框的样式和按钮。默认值为 0。

    Returns:
        int: 用户点击消息框按钮后返回的值，表示用户的选择。
    """
    return ctypes.windll.user32.MessageBoxW(parent_hwnd, text, title, type)




def Checkout_Has_Msedge_Process(_process_name:str="msedge.exe"):
    """检查是否存在指定名称的进程
        
        Args:
            _process_name (str): 进程名称
        
        Returns:
            bool: 如果存在指定名称的进程，则返回 True，否则返回 False
        
        Example:
            >>> CheckMsEdgeProcess('msedge.exe')
            True
        """
    _is_process_running = False
    for _proc in psutil.process_iter(['name']):
        if _proc.info['name'] == _process_name:
            _is_process_running = True
            break
    return _is_process_running




def Checkout_Debug_Mode_Activate() -> bool:
    """
    检查调试模式路径是否可用

    Returns:
        bool: 如果调试模式路径可用，则返回 True，否则返回 False

    Example:
        >>> MyEdge.CheckOutDebugModePath()
        True
    """
    url = "http://127.0.0.1:9652/json/version"
    try:
        response = requests.get(url=url)
        if response.status_code == 200:
            result = True
        else:
            result = False
    except Exception as e:
        print(f"请求调试模式路径时发生错误: {e}")
        result = False
    return result




def Close_All_Msedge_Process(_process_name: str="msedge.exe") -> bool:
    """
    关闭所有指定名称的进程

    Args:
        _process_name (str): 进程名称

    Returns:
        bool: 如果成功关闭所有指定名称的进程，则返回 True，否则返回 False

    Example:
        >>> MyEdge.CloseAllMsEdgeProcess('msedge.exe')
        True
    """
    success = True  # 初始化返回值
    for proc in psutil.process_iter(['pid', 'name']):
        if _process_name == proc.info['name']:
            try:
                proc.kill()  # 关闭进程
                print(f"Closed Microsoft Edge process with PID: {proc.info['pid']}")
            except Exception as e:
                print(f"Failed to close Microsoft Edge process with PID: {proc.info['pid']}. Error: {e}")
                success = False  # 如果关闭失败，设置返回值为 False
    return success




def Start_Debugmode_Browser():
    # 定义启动命令
    # command = r'"C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" --remote-debugging-port=9652 --disable-extensions "http://127.0.0.1:9652/json/version" "https://fxg.jinritemai.com/ffa/mshop/homepage/index" "https://myseller.taobao.com/home.htm/QnworkbenchHome/"'
    command = r'"C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" --remote-debugging-port=9652 --user-data-dir="D:\EdgeAutoCache" "http://127.0.0.1:9652/json/version"'
    
    # 启动新的进程
    CREATE_NEW_CONSOLE = 0x00000010
    subprocess.Popen(command, shell=True, creationflags=CREATE_NEW_CONSOLE)




def Start_Debugmode_Browser_With_Extensions():
    # 定义启动命令
    # command = r'"C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" --remote-debugging-port=9652 "http://127.0.0.1:9652/json/version" "https://fxg.jinritemai.com/ffa/mshop/homepage/index" "https://myseller.taobao.com/home.htm/QnworkbenchHome/"'
    command = r'"C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" --remote-debugging-port=9652 --user-data-dir="D:\EdgeAutoCache" "http://127.0.0.1:9652/json/version"'
    
    # 启动新的进程
    CREATE_NEW_CONSOLE = 0x00000010
    subprocess.Popen(command, shell=True, creationflags=CREATE_NEW_CONSOLE)




def Fast_Create_WebDriver_Wait_Action() -> typing.Tuple[WebDriver, WebDriverWait, ActionChains]:
    """快速创建 WebDriver、WebDriverWait 和 ActionChains 实例。

    Returns:
        typing.Tuple[WebDriver, WebDriverWait, ActionChains]: 返回 WebDriver、WebDriverWait 和 ActionChains 实例的元组。
    """
    options = Options()
    options.add_experimental_option("debuggerAddress", "127.0.0.1:9652")
    service = Service()
    driver = WebDriver(options=options, service=service)
    wait = WebDriverWait(driver=driver,timeout=10)
    actions = ActionChains(driver=driver)
    return driver,wait,actions






def Goto_CurrentActivateUrl(driver: WebDriver) -> None:
    """使用 requests 获取当前激活的页面的 url,并切换到当前激活的页面.

    Args:
        driver (WebDriver): WebDriver 实例

    Returns:
        _type_: None
    """
    debug_json_data = requests.get(
        url="http://127.0.0.1:9652/json", timeout=5).json()

    # 判断获取回来的数据是否正确
    if not isinstance(debug_json_data, list):
        print("接口返回数据格式不正确（非列表或为空）")
        return None

    # 过来掉不需要的 page 页面
    filter_json_data = list(
                                    filter(lambda item: (
                                        item['type'] == "page" and
                                        not item['title'].lower().startswith("devtools") and
                                        not item['title'].lower().startswith("offscreen") and
                                        not item['title'].lower().startswith("新标签页") and
                                        not item['url'].lower().startswith("edge://newtab/") and
                                        not item['url'].lower().startswith("chrome-extension") and
                                        not item['url'].lower().startswith("chrome-devtools")
                                    ), debug_json_data)
                                )
    current_activate_handle = filter_json_data[0]['id']
    driver.switch_to.window(current_activate_handle)
            




def _Find_input_element(driver:WebDriver,wait:WebDriverWait,actions:ActionChains,label:str) -> WebElement:
    anchor_element = driver.find_elements(by=By.XPATH,value=f"//*[(self::span or self::label or self::div) and text()='{label}']")
    if len(anchor_element) == 1:
        find_xpath_path = "./parent::*//input"
        while True:
            try:
                element = anchor_element[0].find_element(by=By.XPATH,value=find_xpath_path)
                return element
            except NoSuchElementException:
                print(f"提示 : 当前层级没有找到 Input 元素,继续向上查找!")
                find_xpath_path = find_xpath_path.replace("//input","/parent::*//input")
                continue
            




def _Find_ByType_input_element(driver:WebDriver,wait:WebDriverWait,actions:ActionChains,label:str,InputType:typing.Literal["","text","file"]="text",InputAccept:typing.Literal['',"video","mp4","image"]="",Multiple:bool=False,max_attempts:int = 5) -> WebElement:
    """该函数用于查找输入元素。
    """
    # 锚点元素必须是全局唯一的
    print(f"//*[(self::span or self::label or self::div) and text()='{label}']")
    elements = driver.find_elements(by=By.XPATH,value=f"//*[(self::span or self::label or self::div) and text()='{label}']")

    if elements.__len__() == 1:
        anchor_element = elements[0]
        find_xpath_path = f"./parent::*"
        input_xpath = "input"
        
        if InputType != "":
            input_xpath += f"[@type='{InputType}']"
        if InputAccept != "":
            input_xpath += f"[contains(@accept,'{InputAccept}')]"
        if Multiple == True:
            input_xpath += f"[@multiple]"
        
        find_xpath_path = f"./parent::*//{input_xpath}"

        attempt = 0
        while True:
            try:
                print(f"提示 : ./parent::*//{input_xpath}")
                element = anchor_element.find_element(by=By.XPATH,value=find_xpath_path)
                return element
            except NoSuchElementException:
                # print(f"提示 : 当前层级没有找到 Input 元素,继续向上查找!")
                # find_xpath_path = find_xpath_path.replace(f"//{input_xpath}",f"/parent::*//{input_xpath}")
                attempt += 1
                anchor_element = anchor_element.find_element(by=By.XPATH,value="./parent::*")
                
                if attempt >= max_attempts:
                    print(f"提示 : 尝试次数已达到最大值,退出查找!")
                    break
                else:
                    continue
    else:
        print(f"提示 : 锚点元素必须是全局唯一的!当前锚点元素个数 : {elements.__len__()}")





def GetDirectory_Picture_List(directory_path:str)->list:
    """
    获取目录下所有图片文件
    """
    picture_list = []
    for root,dirs,files in os.walk(directory_path):
        for file in files:
            if file.endswith(".jpg") or file.endswith(".png") or file.endswith(".jpeg") or file.endswith("webp"):
                picture_list.append(pathlib.Path(os.path.join(root,file)).absolute().resolve().__str__())
    return picture_list





def GetPicture_Join_Text(picture_list:list)->str:
    """
    将图片列表转换为文本
    """
    picture_list_str = ""
    for index, picture_name in enumerate(picture_list):
        picture_path = str(pathlib.Path(picture_name).absolute().resolve())
        if index > 0:  # 不是第一个元素时才添加换行符
            picture_list_str += "\n"
        picture_list_str += picture_path
    return picture_list_str





def GetExistsDirectory(FilterList:list)->str:
    DetailImageDirectory = ""
    for item in FilterList:
        if pathlib.Path(item).absolute().resolve().exists():
            DetailImageDirectory = pathlib.Path(item).absolute().resolve()
            break
    return DetailImageDirectory





def Find_MainImageTitle(driver:WebDriver,wait:WebDriverWait,actions:ActionChains,Picture_Path:str,Delay:float=5):
    """根据图片路径在淘宝网搜索同款!

    Args:
        driver (WebDriver): WebDriver 实例
        wait (WebDriverWait): WebDriverWait 实例
        actions (ActionChains): ActionChains 实例
        Picture_Path (str): 图片路径
    """
    driver.switch_to.new_window("tab")
    driver.get(url="https://s.taobao.com/search?")
    
    try:
        wait_element_xpath_value = f"//div[@class='image-icon-text' and text()='搜同款']"
        wait.until(expected_conditions.presence_of_element_located(locator=(By.XPATH,wait_element_xpath_value)))
    except TimeoutException:
        print(f"提示 : 网页加载失败!\n已退出!")
        return 
    
    try:
        target_element_xpath_value = f"//div[@class='image-icon-text' and text()='搜同款']"
        element = wait.until(expected_conditions.visibility_of_element_located(locator=(By.XPATH,target_element_xpath_value)))
        try:
            element.click()
        except (ElementClickInterceptedException,ElementNotInteractableException):
            driver.execute_script("arguments[0].click();",element)
    except TimeoutException:
        print(f"提示 : 获取元素失败!\n已退出!")
        return
    
    try:
        wait_element_xpath_value = f"//div[contains(@class,'image-search-context-wrapper-active')]//input[@type='file']"
    except TimeoutException:
        print(f"提示 : 打开上传图片对话框失败!\n已退出!")
        return

    try:
        target_element_xpath_value = f"//div[contains(@class,'image-search-context-wrapper-active')]//input[@type='file']"
        element = wait.until(expected_conditions.presence_of_element_located(locator=(By.XPATH,target_element_xpath_value)))
        element.send_keys(pathlib.Path(Picture_Path).absolute().resolve().__str__())
    except TimeoutException:
        print(f"提示 : 没有找到可以上传图片的元素控件!\n已退出!")
        return
    
    try:
        wait_element_xpath_value  = f"//div[@id='image-search-upload-button' and text()='搜索']"
        wait.until(expected_conditions.presence_of_element_located(locator=(By.XPATH,wait_element_xpath_value)))
    except TimeoutException:
        print(f"提示 : 图片上传失败!\n已退出!")
        return
    
    try:
        target_element_xpath_value = f"//div[@id='image-search-upload-button' and text()='搜索']"
        element = wait.until(expected_conditions.presence_of_element_located(locator=(By.XPATH,target_element_xpath_value)))
        try:
            element.click()
        except (ElementClickInterceptedException,ElementNotInteractableException):
            driver.execute_script("arguments[0].click();",element)
    except TimeoutException:
        print(f"提示 : 没有找到开始搜索同款的按钮!\n已退出!")
        return

    time.sleep(Delay)
    driver.execute_script(open(file="./js/淘宝搜同款标题辅助文件.js",mode="r",encoding="utf-8").read())





def download_comment_images(comment_index, image_url_list, comments_root_dir, user_agent, comment_text=None,comment_type=None):
    """
    下载一条评论的文本和图片信息

    :param comment_index: 评论序号（从1开始）
    :param image_url_list: 图片链接列表（可以为空）
    :param comments_root_dir: 主目录 comments-<时间>，由外部创建
    :param user_agent: 浏览器 User-Agent，用于下载图片
    :param comment_text: 评论文本内容（str）
    """

    # 子目录：comment_<index>
    comment_dir = os.path.join(comments_root_dir, f"{comment_type}_{comment_index}")
    os.makedirs(comment_dir, exist_ok=True)

    # 保存文本：comment_text.txt
    text_file_path = os.path.join(comment_dir, "comment_text.txt")
    with open(text_file_path, "w", encoding="utf-8") as f:
        f.write(comment_text or "")

    # 下载图片（如果有）
    headers = {"User-Agent": user_agent}
    for i, img_url in enumerate(image_url_list):
        try:
            response = requests.get(img_url, headers=headers, timeout=10)
            response.raise_for_status()
            img_ext = os.path.splitext(img_url)[-1].split('?')[0] or ".jpg"
            img_path = os.path.join(comment_dir, f"image-{i + 1}{img_ext}")
            with open(img_path, "wb") as img_file:
                img_file.write(response.content)
            print(f"图片已保存: {img_path}")
        except Exception as e:
            print(f"图片下载失败: {img_url} -> {e}")

# 
# 
# 
# 
# 



if __name__ == '__main__':
    import selenium.webdriver

    # 切换工作目录到脚本所在路径
    os.chdir(pathlib.Path(__file__).parent.absolute().resolve().__str__())

    # 创建 driver + 等待器等
    driver, wait, actions = Fast_Create_WebDriver_Wait_Action()
    Goto_CurrentActivateUrl(driver=driver)

    # 获取 user-agent，用于下载图片时 headers 使用
    user_agent = driver.execute_script("return navigator.userAgent;")

    # 创建统一的主下载目录
    now_str = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
    base_download_dir = os.path.abspath(".")
    comments_root_dir = os.path.join(base_download_dir, f"tb_comments-{now_str}")
    os.makedirs(comments_root_dir, exist_ok=True)

    # 等待评论加载完毕
    comments_wrapper_count = 0
    while True:
        comments_wrapper = driver.find_elements(By.XPATH, "//div[contains(@class,'comments')]/div[contains(@class,'Comment')]")
        comments_wrapper_count = len(comments_wrapper)
        driver.execute_script("arguments[0].scrollIntoView();", comments_wrapper[-1])
        time.sleep(0.5)
        new_count = len(driver.find_elements(By.XPATH, "//div[contains(@class,'comments')]/div[contains(@class,'Comment')]"))
        if new_count == comments_wrapper_count:
            print(f"提示 : 当前页面已获取到所有评论，共 {comments_wrapper_count} 条评论！")
            driver.execute_script("arguments[0].scrollIntoView();", comments_wrapper[1])
            break

    # 遍历评论
    comments_wrapper = driver.find_elements(By.XPATH, "//div[contains(@class,'comments')]/div[contains(@class,'Comment')]")
    driver.execute_script("arguments[0].scrollIntoView();", comments_wrapper[1])

    for index, comment_wrapper in enumerate(comments_wrapper, start=1):
        try:
            info_username = comment_wrapper.find_element(By.XPATH, "./div[contains(@class,'header')]/div[contains(@class,'userInfo')]/div[contains(@class,'userName')]/span").text
            info_commentdate = comment_wrapper.find_element(By.XPATH, "./div[contains(@class,'header')]//div[contains(@class,'meta')]").text
            comment_content = comment_wrapper.find_element(By.XPATH, "./div[contains(@class,'contentWrapper')]/div[position() = 1]").text
            comment_type = comment_wrapper.find_element(By.XPATH, "./div[contains(@class,'header')]//div[contains(@class,'meta')]").text.split(" · ")[1].replace("/","")
            
            # 跳到评论容器
            driver.execute_script("arguments[0].scrollIntoView({block: 'center', inline: 'center'});",comment_wrapper)
            
            # 跳过默认好评
            if comment_content.strip() == "该用户未及时主动评价，系统默认好评":
                continue
            

            # 获取评论图片
            comment_img_list = comment_wrapper.find_elements(By.XPATH, "./div[contains(@class,'contentWrapper')]//img")
            comment_img_url_list = [img.get_attribute("src") for img in comment_img_list if img.get_attribute("src")]

            # 输出调试信息
            print(f"\n[{index}] 用户名: {info_username}")
            print(f"时间: {info_commentdate}")
            print(f"内容: {comment_content}")
            print(f"图片数量: {len(comment_img_url_list)}")
            print(f"评论类型 : {comment_type}")
            
            # 过滤
            filter_text_list = [
                "不好",
                "很差",
                "垃圾",
                "差劲",
                "该用户觉得商品非常好，给出好评",
                "该用户未及时主动评价，系统默认好评"
            ]
            
            if any(keyword in comment_content for keyword in filter_text_list):
                continue

            
            
            # 下载评论内容和图片
            download_comment_images(
                comment_index=index,
                image_url_list=comment_img_url_list,
                comments_root_dir=comments_root_dir,   # ✅ 正确的参数名
                user_agent=user_agent,
                comment_text=comment_content,
                comment_type=comment_type
            )


        except Exception as e:
            print(f"处理第 {index} 条评论时出错: {e}")
